use chrono::{DateTime, Local};
use gpui::*;
use gpui_component::{
    Disableable, Icon, StyledExt,
    button::{Button, ButtonVariants},
    input::{InputEvent, InputState, TextInput},
    label::Label,
    switch::Switch,
};
use regex::Regex;

use crate::{constant, notify};

pub struct MainApp {
    now_time: SharedString,
    state: constant::State,
    input_state: Entity<InputState>,
    message_state: Entity<InputState>,
    message: SharedString,
    time_tick: u16,
    next_alarm_time: Option<DateTime<Local>>,
    repeat: bool,
    _task: Task<()>,
    _subscribe: Subscription,
    _subscribe2: Subscription,
}

impl MainApp {
    pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
        let input_state = cx.new(|cx| {
            InputState::new(window, cx)
                .pattern(Regex::new(r"^\d+$").unwrap())
                .validate(|v, _| v.parse::<u16>().is_ok())
                .default_value("10")
        });

        let message_state = cx.new(|cx| {
            InputState::new(window, cx)
                .validate(|v, _| !v.is_empty())
                .default_value("起来走动一下吧")
        });

        let _task = cx.spawn(async move |this, cx| {
            loop {
                cx.background_executor()
                    .timer(std::time::Duration::from_secs(1))
                    .await;
                let now = Local::now();
                let _ = this.update(cx, |this, cx| {
                    this.now_time = now.format("%H:%M:%S").to_string().into();
                    if constant::State::Stop == this.state {
                        if let Some(next_alarm_time) = this.next_alarm_time {
                            if next_alarm_time <= now {
                                notify::notify(this.time_tick, this.message.as_ref());
                                this.next_alarm_time = match this.repeat {
                                    true => Some(
                                        now.checked_add_signed(chrono::Duration::minutes(
                                            this.time_tick as i64,
                                        ))
                                        .unwrap(),
                                    ),
                                    false => {
                                        this.state = constant::State::Start;
                                        None
                                    }
                                };
                            }
                        }
                    }
                    cx.notify();
                });
            }
        });

        let _subscribe = cx.subscribe_in(&input_state, window, {
            let input_state = input_state.clone();
            move |this, _, ev: &InputEvent, _window: &mut Window, cx| match ev {
                InputEvent::Change => {
                    let value = input_state.read(cx).value();
                    this.time_tick = value.parse::<u16>().unwrap_or(10u16);
                }
                _ => {}
            }
        });

        let _subscribe2 = cx.subscribe_in(&message_state, window, {
            let message_state = message_state.clone();
            move |this, _, ev: &InputEvent, _window: &mut Window, cx| match ev {
                InputEvent::Change => {
                    this.message = message_state.read(cx).value();
                }
                _ => {}
            }
        });

        Self {
            now_time: Local::now().format("%H:%M:%S").to_string().into(),
            state: constant::State::Start,
            input_state,
            message_state,
            message: "起来走动一下吧".into(),
            time_tick: 10u16,
            next_alarm_time: None,
            repeat: true,
            _task,
            _subscribe,
            _subscribe2,
        }
    }

    fn update_state(&mut self, _: &ClickEvent, _window: &mut Window, cx: &mut Context<Self>) {
        match self.state {
            constant::State::Start => {
                self.state = constant::State::Stop;
                self.next_alarm_time = Some(
                    Local::now()
                        .checked_add_signed(chrono::Duration::minutes(self.time_tick as i64))
                        .unwrap(),
                );
            }
            constant::State::Stop => {
                self.state = constant::State::Start;
                self.next_alarm_time = None;
            }
        }
        cx.notify();
    }

    fn disabled(&self) -> bool {
        constant::State::Stop == self.state
    }
}

impl Render for MainApp {
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        let button = Button::new("state")
            .w_full()
            .h_10()
            .primary()
            .label(&self.state.to_string())
            .icon(match self.state {
                constant::State::Start => Icon::empty().path("icons/timer.svg"),
                constant::State::Stop => Icon::empty().path("icons/timer-off.svg"),
            })
            .on_click(cx.listener(Self::update_state));

        let div = div()
            .v_flex()
            .flex_auto()
            .p_5()
            .gap_3()
            .size_full()
            .items_center()
            .child(
                Label::new(self.now_time.clone())
                    .text_size(AbsoluteLength::Rems(Rems(4.)))
                    .mt(px(-20.))
                    .font_bold(),
            )
            .child(
                TextInput::new(&self.message_state)
                    .w_full()
                    .border(px(2.))
                    .border_color(rgb(0x419dff))
                    .disabled(self.disabled())
                    .prefix(Icon::empty().path("icons/message.svg")),
            )
            .child(
                TextInput::new(&self.input_state)
                    .w_full()
                    .border(px(2.))
                    .border_color(rgb(0x419dff))
                    .disabled(self.disabled())
                    .prefix(Icon::empty().path("icons/alarm-clock.svg"))
                    .suffix(Label::new("分钟").font_bold()),
            )
            .child(
                Switch::new("repeat")
                    .label("重复")
                    .disabled(self.disabled())
                    .checked(self.repeat)
                    .on_click(cx.listener(|this, checked, _, cx| {
                        this.repeat = *checked;
                        cx.notify();
                    })),
            )
            .child(button);

        if constant::State::Stop == self.state {
            div.child(
                Label::new(
                    self.next_alarm_time
                        .clone()
                        .unwrap_or(Local::now())
                        .format("%H:%M:%S")
                        .to_string(),
                )
                .text_color(rgb(0xcc4444))
                .text_size(AbsoluteLength::Rems(Rems(4.)))
                .font_bold(),
            )
        } else {
            div
        }
    }
}
